home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1994 November / macformat-018.iso / Utility Spectacular / Developer / macgambit-20-compiler-src-p1 / Runtime (.c & .h) / stats.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-26  |  16.0 KB  |  680 lines  |  [TEXT/KAHL]

  1. /* Statistics gathering */
  2.  
  3. #include "params.h"
  4. #include "gambit.h"
  5. #include "struct.h"
  6. #include "os.h"
  7. #include "mem.h"
  8. #include "strings.h"
  9. #include "run.h"
  10.  
  11.  
  12. /*---------------------------------------------------------------------------*/
  13.  
  14.  
  15. #define MAX_STAT_NAME_LENGTH 256
  16.  
  17. struct stat_rec {
  18.   char *name;
  19.   long count;
  20.   struct stat_list *sub_parts;
  21.   };
  22.  
  23. typedef struct stat_rec *STAT_PTR;
  24.  
  25. struct stat_list {
  26.   struct stat_rec stat;
  27.   struct stat_list *next;
  28.   };
  29.  
  30. typedef struct stat_list *STAT_LIST_PTR;
  31.  
  32. char stat_name[MAX_STAT_NAME_LENGTH+1];
  33. long stat_multiplier;
  34.  
  35. char *predefined_stats[] = PREDEFINED_STATS;
  36.  
  37. #define NB_PREDEFINED_STATS (sizeof(predefined_stats) / sizeof(char *))
  38.  
  39. char *events[] = EVENTS;
  40.  
  41. #define NB_EVENTS (sizeof(events) / sizeof(char *))
  42.  
  43. struct stat_rec stat_root;
  44. STAT_PTR prof_category, event_prof_category;
  45.  
  46. PSTATE_PTR processor;
  47.  
  48. char *prog_filename;
  49.  
  50.  
  51. /*---------------------------------------------------------------------------*/
  52.  
  53.  
  54. void init_stats()
  55. { sstate->nb_stats = NB_PREDEFINED_STATS;
  56. }
  57.  
  58.  
  59. long alloc_stat( index )
  60. long *index;
  61. { if (sstate->nb_stats >= MAX_NB_STATS) return 1;
  62.   *index = sstate->nb_stats++;
  63.   return 0;
  64. }
  65.  
  66.  
  67. void stats_clear( index )
  68. long index;
  69. { sstate->ofile[index].stats_bot = 0;
  70.   sstate->ofile[index].stats_top = 0;
  71. }
  72.  
  73.  
  74. void stats_begin( index )
  75. long index;
  76. { sstate->ofile[index].stats_bot = sstate->nb_stats;
  77. }
  78.  
  79.  
  80. void stats_end( index )
  81. long index;
  82. { sstate->ofile[index].stats_top = sstate->nb_stats;
  83. }
  84.  
  85.  
  86. /*---------------------------------------------------------------------------*/
  87.  
  88.  
  89. char *ofile_start;
  90.  
  91.  
  92. void read_ofile( index )
  93. long index;
  94. { if (sstate->ofile[index].len == 0)
  95.   { OS_FILE input;
  96.     char *filename;
  97.     long len;
  98.     char *top;
  99.  
  100.     ofile_start = pstate->heap_old;
  101.     top = ofile_start + (pstate->heap_mid - pstate->heap_bot);
  102.  
  103.     filename = string_append( sstate->ofile[index].ptr, ".O" );
  104.     if (filename == NULL)
  105.     { os_warn( "Local memory overflow\n", 0L ); os_quit(); }
  106.     input = os_file_open_input( filename );
  107.     if (input == -1)
  108.     { os_warn( "Can't open %s\n", (long)filename ); os_quit(); }
  109.     len = os_file_length( input );
  110.     if (len < 0)
  111.     { os_warn( "Read error on object file %s\n", (long)filename ); os_quit(); }
  112.  
  113.     if (ofile_start+len > top)
  114.     { os_file_close( input ); os_warn( "Load memory overflow\n", 0L ); os_quit(); }
  115.  
  116.     if (os_file_read( input, ofile_start, len ) != len)
  117.     { os_file_close( input ); os_warn( "Read error on object file %s\n", (long)filename ); os_quit(); }
  118.  
  119.     os_file_close( input );
  120.   }
  121.   else
  122.     ofile_start = sstate->ofile[index].ptr;
  123. }
  124.  
  125.  
  126. char *parse_ptr;
  127.  
  128.  
  129. char parse_stat_name()
  130. { long len = 0;
  131.   long level = 0;
  132.   long sign;
  133.   char c = *(parse_ptr++);
  134.   while ((c > ' ') || (level > 0))
  135.     { if (len > MAX_STAT_NAME_LENGTH)
  136.       { os_warn( "Stat name too long\n", 0L ); os_quit(); }
  137.     stat_name[len++] = c;
  138.     if (c == '(') level++; else if (c == ')') level--;
  139.     c = *(parse_ptr++);
  140.   }
  141.   stat_name[len] = '\0';
  142.   stat_multiplier = 0;
  143.   while ((c > '\0') && (c <= ' ')) c = *(parse_ptr++);
  144.   if (c == '-') { sign = -1; c = *(parse_ptr++); }
  145.   else if (c == '+') { sign = 1; c = *(parse_ptr++); }
  146.   else sign = 1;
  147.   while ((c >= '0') && (c <= '9'))
  148.   { stat_multiplier = stat_multiplier*10 + (c - '0');
  149.     c = *(parse_ptr++);
  150.   }
  151.   stat_multiplier = sign * stat_multiplier;
  152.   return c;
  153. }
  154.  
  155.  
  156. STAT_PTR enter_sub_part( s, name )
  157. STAT_PTR s;
  158. char *name;
  159. { STAT_LIST_PTR ptr = s->sub_parts;
  160.  
  161.   while (ptr != NULL)
  162.   { char *p1 = ptr->stat.name, *p2 = name;
  163.     while ((*p1 != '\0') && (*p1 == *p2)) { p1++; p2++; }
  164.     if (*p1 == *p2) break; /* found entry */
  165.     ptr = ptr->next;
  166.   }
  167.  
  168.   if (ptr != NULL)
  169.     return &ptr->stat;
  170.   else
  171.   { STAT_LIST_PTR new = (STAT_LIST_PTR)local_malloc8( (long)sizeof(struct stat_list) );
  172.     if (new == NULL)
  173.     { os_warn( "Couldn't allocate stat entry\n", 0L ); os_quit(); }
  174.  
  175.     new->stat.name = string_copy( name );
  176.     if (new->stat.name == NULL)
  177.     { os_warn( "Couldn't allocate stat entry name\n", 0L ); os_quit(); }
  178.  
  179.     new->stat.count = 0;
  180.     new->stat.sub_parts = NULL;
  181.     new->next = s->sub_parts;
  182.     s->sub_parts = new;
  183.     return &new->stat;
  184.   }
  185. }
  186.  
  187.  
  188. void parse_sub_parts( s, count, c )
  189. STAT_PTR s;
  190. long count;
  191. char c;
  192. { STAT_PTR sub;
  193.  
  194.   loop:
  195.  
  196.   while ((c > '\0') && (c <= ' ')) c = *(parse_ptr++);
  197.  
  198.   switch (c)
  199.   { case ')': return;
  200.     case '(': c = parse_stat_name();
  201.               sub = enter_sub_part( s, stat_name );
  202.               sub->count += stat_multiplier * count;
  203.               parse_sub_parts( sub, count, c );
  204.               c = *(parse_ptr++);
  205.               goto loop;
  206.     default:
  207.       { os_warn( "Incorrect statistic format\n", 0L ); os_quit(); }
  208.     }
  209. }
  210.  
  211.  
  212. void parse_stat( count )
  213. long count;
  214. { char c = *(parse_ptr++);
  215.   while ((c > '\0') && (c <= ' ')) c = *(parse_ptr++);
  216.   if (c != '(')
  217.   { os_warn( "Incorrect statistic format, '(' expected\n", 0L ); os_quit(); }
  218.   c = *(parse_ptr++);
  219.   parse_sub_parts( &stat_root, count, c );
  220. }
  221.  
  222.  
  223. void enter_stat( stat, index )
  224. char *stat;
  225. long index;
  226. { long count = processor->stats_counters[index];
  227.   if (count > 0)
  228.   { parse_ptr = stat; parse_stat( count ); }
  229. }
  230.  
  231.  
  232. void enter_prof_stat( adr, length, name )
  233. long adr, length;
  234. char *name;
  235. { long end = adr + length;
  236.   if (name == NULL)
  237.   { os_warn( "Local memory overflow\n", 0L ); os_quit(); }
  238.   if ((adr >= (long)sstate->const_bot) && (end < (long)sstate->const_top))
  239.   { short *p = &processor->prof_bot[(adr-(long)sstate->const_bot)>>PROF_SHIFT];
  240.     long ticks = 0;
  241.     long i;
  242.     for (i=length+4; i>0; i -= 1<<PROF_SHIFT) { ticks += *p; *(p++) = 0; }
  243.     if (ticks > 0)
  244.     { long msec = os_ticks_to_msec( ticks );
  245.       STAT_PTR s = enter_sub_part( prof_category, name );
  246.       prof_category->count += msec;
  247.       s->count += msec;
  248.     }
  249.   }
  250. }
  251.  
  252.  
  253. void add_prof_stat( msec, name )
  254. long msec;
  255. char *name;
  256. { if (msec > 0)
  257.   { STAT_PTR s = enter_sub_part( prof_category, name );
  258.     prof_category->count += msec;
  259.     s->count += msec;
  260.   }
  261. }
  262.  
  263.  
  264. void stats_compute_profile()
  265. { short *p;
  266.   long ticks;
  267.   long cpu = (pstate->cpu_times[0] - pstate->stats_cpu_times[0]) +
  268.              (pstate->cpu_times[1] - pstate->stats_cpu_times[1]);
  269.   
  270.   prof_category = enter_sub_part( &stat_root, "profile" );
  271.  
  272.   for_each_glob_prim_proc( enter_prof_stat );
  273.  
  274.   p = processor->prof_bot;
  275.   ticks = 0;
  276.   while (p < processor->prof_top) ticks += *(p++);
  277.  
  278.   if (ticks > 0)
  279.     add_prof_stat( os_ticks_to_msec( ticks ), "(non_global_procedures)" );
  280.  
  281.   add_prof_stat( cpu-prof_category->count, "(unaccounted_for)" );
  282. }
  283.  
  284.  
  285. #define EVENT(x,y) (((x)<<24)+(y))
  286. #define EVENT_NUM(x) ((x)>>24)
  287. #define EVENT_TIME(x) ((x) & 0xffffff)
  288. #define REL_TIME(x) EVENT_TIME((x)-elog_start)
  289. #define LATER(x,y) ((y)-(x) & 0x800000)
  290. long *elog_ptr[MAX_NB_PROC], *elog_top[MAX_NB_PROC];
  291. long elog_start, elog_end;
  292.  
  293. #define ELOG_BUF_SIZE 1024
  294. char *elog_buf;
  295. long elog_len;
  296.  
  297.  
  298. void elog_setup( start_time, stop_time )
  299. long start_time, stop_time;
  300. { long i;
  301.  
  302.   elog_start = EVENT_TIME(start_time);
  303.   elog_end = EVENT_TIME(stop_time);
  304.  
  305.   for (i=SCM_obj_to_int(pstate->nb_processors)-1; i>=0; i--)
  306.   { long *p1, *p2;
  307.     processor = pstate->ps[i];
  308.     p1 = processor->elog_ptr;
  309.     p2 = processor->elog_top;
  310.     while ((p1 < p2) && LATER(EVENT_TIME(p1[0]), elog_end)) p1++;
  311.     while ((p1 < p2) && LATER(elog_start, EVENT_TIME(p2[-1]))) p2--;
  312.     elog_ptr[i] = p1;
  313.     elog_top[i] = p2;
  314.   }
  315. }
  316.  
  317.  
  318. void elog_begin()
  319. { elog_buf = (char *)local_malloc8( (long)ELOG_BUF_SIZE );
  320.   if (elog_buf == NULL)
  321.   { os_warn( "Couldn't allocate elog buffer\n", 0L ); os_quit(); }
  322.   elog_len = 0;
  323. }
  324.  
  325.  
  326. void elog_finish( output )
  327. OS_FILE output;
  328. { if (elog_len > 0) os_file_write( output, elog_buf, elog_len );
  329. }
  330.  
  331.  
  332. void elog_char( output, c )
  333. OS_FILE output;
  334. char c;
  335. { elog_buf[elog_len++] = c;
  336.   if (elog_len >= (long)ELOG_BUF_SIZE)
  337.   { os_file_write( output, elog_buf, elog_len );
  338.     elog_len = 0;
  339.   }
  340. }
  341.  
  342.  
  343. void elog_long( output, val )
  344. OS_FILE output;
  345. long val;
  346. { char *p = (char *)&val;
  347.   long i;
  348.   for (i=(long)sizeof(val); i>0; i--)
  349.   { elog_buf[elog_len++] = *p++;
  350.     if (elog_len >= (long)ELOG_BUF_SIZE)
  351.     { os_file_write( output, elog_buf, elog_len );
  352.       elog_len = 0;
  353.     }
  354.   }
  355. }
  356.  
  357.  
  358. void elog_generate()
  359. { if (elog_start != elog_end)
  360.   { OS_FILE output;
  361.     long i;
  362.     char *mark = local_mark();
  363.  
  364.     output = os_file_open_output( string_append( prog_filename, ".elog" ) );
  365.     if (output == -1)
  366.     { os_warn( "Can't open event log file\n", 0L ); os_quit(); }
  367.  
  368.     elog_begin();
  369.  
  370.     elog_long( output, 12L );
  371.     elog_long( output, 1L );
  372.     elog_long( output, 0x80000000L );
  373.     elog_long( output, 2L );
  374.  
  375.     for (i=0; i<NB_EVENTS; i++)
  376.     { long j, len = string_length( events[i] );
  377.       elog_long( output, (((len+2+3)/sizeof(long))+2)*sizeof(long) );
  378.       elog_long( output, 2L );
  379.       elog_long( output, i+1 );
  380.       for (j=0; j<len; j++) elog_char( output, events[i][j] );
  381.       elog_char( output, '\0' );
  382.       elog_char( output, '\0' );
  383.       for (j=j+2; j%sizeof(long)!=0; j++) elog_char( output, '\0' );
  384.     }
  385.  
  386.     for (i=0; i<SCM_obj_to_int(pstate->nb_processors); i++)
  387.     { long *p;
  388.       long len;
  389.       p = elog_top[i];
  390.       len = p-elog_ptr[i];
  391.       elog_long( output, (len*3+5)*sizeof(long) );
  392.       elog_long( output, 3L );
  393.       elog_long( output, i );
  394.       elog_long( output, 0L );
  395.       elog_long( output, 20L );
  396.       elog_long( output, 0L );
  397.       while (len > 0)
  398.       { long event = *(--p);
  399.         len--;
  400.         elog_long( output, REL_TIME(EVENT_TIME(event)) );
  401.         elog_long( output, EVENT_NUM(event)+1 );
  402.         elog_long( output, 0L );
  403.       }
  404.     }
  405.  
  406.     elog_finish( output );
  407.  
  408.     os_file_close( output );
  409.  
  410.     local_release( mark );
  411.   }
  412. }
  413.  
  414.  
  415. void add_event_prof_stat( ticks, name )
  416. long ticks;
  417. char *name;
  418. { if (ticks > 0)
  419.   { STAT_PTR s = enter_sub_part( event_prof_category, name );
  420.     event_prof_category->count += ticks;
  421.     s->count += ticks;
  422.   }
  423. }
  424.  
  425.  
  426. void stats_compute_event_profile()
  427. { long *p;
  428.   long i;
  429.   long prof[NB_EVENTS];
  430.  
  431.   event_prof_category = enter_sub_part( &stat_root, "event_profile" );
  432.  
  433.   for (i=0; i<NB_EVENTS; i++) prof[i] = 0;
  434.  
  435.   p = elog_top[SCM_obj_to_int(processor->id)];
  436.   if (p == elog_ptr[SCM_obj_to_int(processor->id)])
  437.     prof[EVENT_IDLE] = REL_TIME(elog_end);
  438.   else
  439.   { long last_event_num = EVENT_IDLE;
  440.     long last_event_time = 0;
  441.     while (p > elog_ptr[SCM_obj_to_int(processor->id)])
  442.     { long event = *(--p);
  443.       long event_num = EVENT_NUM(event);
  444.       long event_time = REL_TIME(EVENT_TIME(event));
  445.       prof[last_event_num] += EVENT_TIME(event_time - last_event_time);
  446.       last_event_num = event_num;
  447.       last_event_time = event_time;
  448.     }
  449.     prof[last_event_num] += EVENT_TIME(REL_TIME(elog_end) - last_event_time);
  450.   }
  451.  
  452.   for (i=0; i<NB_EVENTS; i++)
  453.     add_event_prof_stat( prof[i], events[i] );
  454. }
  455.  
  456.  
  457. void stats_compute()
  458. { long index, i;
  459.  
  460.   stat_root.sub_parts = NULL;
  461.  
  462.   for (i=NB_PREDEFINED_STATS-1; i>=0; i--)
  463.     enter_stat( predefined_stats[i], i );
  464.  
  465.   for (index=0; index<sstate->nb_ofiles; index++)
  466.     if (sstate->ofile[index].stats_top >
  467.         sstate->ofile[index].stats_bot )
  468.     { read_ofile( index );
  469.       for (i=sstate->ofile[index].stats_bot;
  470.            i<sstate->ofile[index].stats_top;
  471.            i++)
  472.         enter_stat( ofile_start+sstate->stats_offsets[i], i );
  473.     }
  474.  
  475.   if (sstate->profiling) stats_compute_profile();
  476.  
  477.   if (elog_start != elog_end) stats_compute_event_profile();
  478. }
  479.  
  480.  
  481. /*---------------------------------------------------------------------------*/
  482.  
  483.  
  484. void sort_sub_parts( s )
  485. STAT_PTR s;
  486. { STAT_LIST_PTR i = s->sub_parts;
  487.  
  488.   while (i != NULL)
  489.   { STAT_LIST_PTR j = i->next, k = i;
  490.     struct stat_rec temp;
  491.  
  492.     while (j != NULL)
  493.     { if (j->stat.count > k->stat.count) k = j;
  494.       j = j->next;
  495.     }
  496.  
  497.     temp = i->stat; i->stat = k->stat; k->stat = temp;
  498.  
  499.     i = i->next;
  500.   }
  501. }
  502.  
  503.  
  504. long thousanths( x, y )
  505. long x, y;
  506. { while (x > 2147483) { x = x>>1; y = y>>1; }
  507.   return x * 1000 / y;
  508. }
  509.  
  510.  
  511. void stats_write_sub_parts( output, s, indent )
  512. OS_FILE output;
  513. STAT_PTR s;
  514. long indent;
  515. { STAT_LIST_PTR ptr;
  516.   long newlines = 0;
  517.  
  518.   sort_sub_parts( s );
  519.  
  520.   ptr = s->sub_parts;
  521.   while (ptr != NULL)
  522.     if (ptr->stat.sub_parts != NULL)
  523.     { newlines = 1; break; }
  524.     else
  525.       ptr = ptr->next;
  526.  
  527.   ptr = s->sub_parts;
  528.   while (ptr != NULL)
  529.   { long i, thous;
  530.     os_file_printf( output, "\n", 0L );
  531.     if (newlines) os_file_printf( output, "\n", 0L );
  532.     for (i=indent; i>0; i--) os_file_printf( output, " ", 0L );
  533.     thous = thousanths( ptr->stat.count, s->count );
  534.     os_file_printf( output, "(", 0L );
  535.     if (thous < 1000) os_file_printf( output, " ", 0L );
  536.     if (thous < 100) os_file_printf( output, " ", 0L );
  537.     os_file_printf( output, "%d", thous/10 );
  538.     os_file_printf( output, ".%d", thous%10 );
  539.     os_file_printf( output, " %s", (long)ptr->stat.name );
  540.     os_file_printf( output, " %d", ptr->stat.count );
  541.     stats_write_sub_parts( output, &ptr->stat, indent+12 );
  542.     os_file_printf( output, ")", 0L );
  543.     ptr = ptr->next;
  544.   }
  545. }
  546.  
  547.  
  548. void stats_write_categories( output, ptr )
  549. OS_FILE output;
  550. STAT_LIST_PTR ptr;
  551. { while (ptr != NULL)
  552.   { os_file_printf( output, "(%s", (long)ptr->stat.name );
  553.     os_file_printf( output, " %d", ptr->stat.count );
  554.     stats_write_sub_parts( output, &ptr->stat, 2L );
  555.     os_file_printf( output, ")\n\n", 0L );
  556.     ptr = ptr->next;
  557.   }
  558. }
  559.  
  560.  
  561. void stats_write( output )
  562. OS_FILE output;
  563. { char *mark = local_mark();
  564.   os_file_printf( output, "( ; *** PROCESSOR %d ***\n\n", SCM_obj_to_int(processor->id) );
  565.   stats_compute();
  566.   sort_sub_parts( &stat_root );
  567.   stats_write_categories( output, stat_root.sub_parts );
  568.   os_file_printf( output, ")\n\n", 0L );
  569.   local_release( mark );
  570. }
  571.  
  572.  
  573. void stats_generate()
  574. { OS_FILE output;
  575.   long i;
  576.   char *p;
  577.  
  578.   prog_filename = sstate->program_filename;
  579.   p = prog_filename;
  580.   while (*p != '\0') if (*p++ == '/') prog_filename = p;
  581.     
  582.   elog_setup( sstate->stats_start_time, sstate->stats_stop_time );
  583.  
  584.   output = os_file_open_output( string_append( prog_filename, ".stats" ) );
  585.   if (output == -1)
  586.   { os_warn( "Can't open statistics file\n", 0L ); os_quit(); }
  587.  
  588.   os_file_printf( output, "(\n\n", 0L );
  589.  
  590.   for (i=0; i<SCM_obj_to_int(pstate->nb_processors); i++)
  591.   { processor = pstate->ps[i];
  592.     stats_write( output );
  593.   }
  594.  
  595.   os_file_printf( output, ")\n", 0L );
  596.  
  597.   os_file_close( output );
  598.  
  599.   elog_generate();
  600. }
  601.  
  602.  
  603. /*---------------------------------------------------------------------------*/
  604.  
  605.  
  606. void stats_start1( id )
  607. long id;
  608. { long i;
  609.  
  610.   if (sstate->profiling)
  611.   { short *p = (short *)pstate->prof_bot;
  612.     os_profil( (short *)NULL, 0L, 0L, 0L );
  613.     while (p < (short *)pstate->prof_top) *(p++) = 0;
  614.   }
  615.  
  616.   for (i=0; i<MAX_NB_STATS; i++) pstate->stats_counters[i] = 0;
  617.  
  618.   if (SCM_obj_to_int(pstate->id) == 0) sstate->stats_on = 1;
  619.  
  620.   if (sstate->profiling)
  621.   { os_cpu_times( pstate->stats_cpu_times );
  622.     os_profil( pstate->prof_bot,
  623.                (long)(pstate->prof_top - pstate->prof_bot),
  624.                (long)sstate->const_bot,
  625.                (long)PROF_SHIFT );
  626.   }
  627.  
  628.   pstate->elog_ptr = pstate->elog_top;
  629.  
  630.   if (id == SCM_obj_to_int(pstate->id))
  631.   { pstate->elog_top[0] = EVENT(EVENT_WORKING,0);
  632.     pstate->elog_top[1] = EVENT(EVENT_WORKING,0);
  633.   }
  634.   else
  635.   { pstate->elog_top[0] = EVENT(EVENT_IDLE,0);
  636.     pstate->elog_top[1] = EVENT(EVENT_IDLE,0);
  637.   }
  638. }
  639.  
  640.  
  641. void stats_start2()
  642. { long start;
  643.   start = os_real_time_clock();
  644.   sstate->stats_start_time = start;
  645.   while (os_clock_to_msec(sstate->stats_start_time - start) < 100)
  646.     sstate->stats_start_time = os_real_time_clock(); /* wait for 100 msec */
  647. }
  648.  
  649.  
  650. long stats_stop1()
  651. { sstate->stats_stop_time = os_real_time_clock();
  652.   if (sstate->profiling)
  653.   { os_profil( (short *)NULL, 0L, 0L, 0L );
  654.     os_cpu_times( pstate->cpu_times );
  655.   }
  656.  
  657.   return os_clock_to_msec( sstate->stats_stop_time - sstate->stats_start_time );
  658. }
  659.  
  660.  
  661. void stats_stop2()
  662. { if ((SCM_obj_to_int(pstate->id) == 0) && sstate->stats_on)
  663.   { sstate->stats_on = 0;
  664.     if ((!sstate->profiling) && (sstate->nb_stats == NB_PREDEFINED_STATS))
  665.     { long i, j;
  666.       for (i=SCM_obj_to_int(pstate->nb_processors)-1; i>=0; i--)
  667.       { if (pstate->ps[i]->elog_ptr != pstate->ps[i]->elog_top) goto stats_gen;
  668.         for (j=sstate->nb_stats-1; j>=FIRST_AUTO_STAT; j--)
  669.           if (pstate->ps[i]->stats_counters[j] != 0) goto stats_gen;
  670.       }
  671.       return;
  672.       stats_gen: ;
  673.     }
  674.     stats_generate();
  675.   }
  676. }
  677.  
  678.  
  679. /*---------------------------------------------------------------------------*/
  680.